// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package httputil

import (
	"bufio"
	"errors"
	"io"
	"net"
	"net/http"
	"net/textproto"
	"sync"
)

var (
	// 已弃用：不再使用。
	ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}

	// 已弃用：不再使用。
	ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}

	// 已弃用：不再使用。
	ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
)

// 这是一个API使用错误-本地端已关闭。
// ErrPersistEOF（如上）报告远程端已关闭。
var errClosed = errors.New("i/o operation on closed connection")

// ServerConn是Go早期HTTP实现的产物。
// 它是低级的、旧的，并且在Go当前的HTTP堆栈中未使用。
// 我们应该在Go 1之前删除它。
// 
// 已弃用：请改用包net/http中的服务器。
type ServerConn struct {
	mu              sync.Mutex // 读写保护以下字段
	c               net.Conn
	r               *bufio.Reader
	re, we          error // 读/写错误
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*http.Request]uint

	pipe textproto.Pipeline
}

// NewServerConn是Go早期HTTP实现的产物。
// 它是低级的、旧的，并且在Go当前的HTTP堆栈中未使用。
// 我们应该在Go 1之前删除它。
// 
// 已弃用：请改用包net/http中的服务器。
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ServerConn{c: c, r: r, pipereq: make(map[*http.Request]uint)}
}

// Hijack会分离ServerConn并返回底层连接以及可能有一些剩余数据的读取端bufio。劫持可能是
// 在Read发出保持活动逻辑结束的信号之前调用的。用户
// 在读取或写入过程中不应调用劫持。
func (sc *ServerConn) Hijack() (net.Conn, *bufio.Reader) {
	sc.mu.Lock()
	defer sc.mu.Unlock()
	c := sc.c
	r := sc.r
	sc.c = nil
	sc.r = nil
	return c, r
}

// Close调用Hijack，然后还关闭底层连接。
func (sc *ServerConn) Close() error {
	c, _ := sc.Hijack()
	if c != nil {
		return c.Close()
	}
	return nil
}

// Read返回连线上的下一个请求。如果
// 正常确定不再有请求（例如，在HTTP/1.0连接上的第一个请求后，或在连接后：在
// HTTP/1.1连接上关闭），则返回ErrPersistEOF。
func (sc *ServerConn) Read() (*http.Request, error) {
	var req *http.Request
	var err error

	// 确保读写操作的有序执行
	id := sc.pipe.Next()
	sc.pipe.StartRequest(id)
	defer func() {
		sc.pipe.EndRequest(id)
		if req == nil {
			sc.pipe.StartResponse(id)
			sc.pipe.EndResponse(id)
		} else {
			// 记住此请求的管道id 
			sc.mu.Lock()
			sc.pipereq[req] = id
			sc.mu.Unlock()
		}
	}()

	sc.mu.Lock()
	if sc.we != nil { // 如果写入端断开或关闭，则没有接收点
		defer sc.mu.Unlock()
		return nil, sc.we
	}
	if sc.re != nil {
		defer sc.mu.Unlock()
		return nil, sc.re
	}
	if sc.r == nil { // 同时由用户关闭连接
		defer sc.mu.Unlock()
		return nil, errClosed
	}
	r := sc.r
	lastbody := sc.lastbody
	sc.lastbody = nil
	sc.mu.Unlock()

	// 确保主体已完全消耗，即使用户不调用body.Close 
	if lastbody != nil {
		// body.Close被假定为幂等函数，并且多次调用
		// 它应该返回其第一次调用
		// 返回的错误。
		err = lastbody.Close()
		if err != nil {
			sc.mu.Lock()
			defer sc.mu.Unlock()
			sc.re = err
			return nil, err
		}
	}

	req, err = http.ReadRequest(r)
	sc.mu.Lock()
	defer sc.mu.Unlock()
	if err != nil {
		if err == io.ErrUnexpectedEOF {
			// 对方客户的成交被视为
			// 漂亮的成交，即使成交前有一些不可分析的
			// 数据。
			sc.re = ErrPersistEOF
			return nil, sc.re
		} else {
			sc.re = err
			return req, err
		}
	}
	sc.lastbody = req.Body
	sc.nread++
	if req.Close {
		sc.re = ErrPersistEOF
		return req, sc.re
	}
	return req, err
}

// Pending返回在连接上接收到的未响应请求
// 的数量。
func (sc *ServerConn) Pending() int {
	sc.mu.Lock()
	defer sc.mu.Unlock()
	return sc.nread - sc.nwritten
}

// 写写响应req。要优雅地关闭连接，请将
// Response.close字段设置为true。在
// /返回错误之前，写操作应被视为可操作的，无论在读端返回任何错误。
func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {

	// 检索此请求/响应对的管道ID 
	sc.mu.Lock()
	id, ok := sc.pipereq[req]
	delete(sc.pipereq, req)
	if !ok {
		sc.mu.Unlock()
		return ErrPipeline
	}
	sc.mu.Unlock()

	// 确保管道顺序
	sc.pipe.StartResponse(id)
	defer sc.pipe.EndResponse(id)

	sc.mu.Lock()
	if sc.we != nil {
		defer sc.mu.Unlock()
		return sc.we
	}
	if sc.c == nil { // 同时用户关闭连接
		defer sc.mu.Unlock()
		return ErrClosed
	}
	c := sc.c
	if sc.nread <= sc.nwritten {
		defer sc.mu.Unlock()
		return errors.New("persist server pipe count")
	}
	if resp.Close {
		// 在发出保持活动关闭信号后，任何管道化的未读
		// 请求将丢失。在发送信号之前，由用户将其排出
		// 中。
		sc.re = ErrPersistEOF
	}
	sc.mu.Unlock()

	err := resp.Write(c)
	sc.mu.Lock()
	defer sc.mu.Unlock()
	if err != nil {
		sc.we = err
		return err
	}
	sc.nwritten++

	return nil
}

// ClientConn是Go早期HTTP实现的产物。
// 它是低级的、旧的，并且在Go当前的HTTP堆栈中未使用。
// 我们应该在Go 1之前删除它。
// 
// 已弃用：改用包net/http中的客户端或传输。
type ClientConn struct {
	mu              sync.Mutex // 读写保护以下字段
	c               net.Conn
	r               *bufio.Reader
	re, we          error // 读/写错误
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*http.Request]uint

	pipe     textproto.Pipeline
	writeReq func(*http.Request, io.Writer) error
}

// NewClientConn是Go早期HTTP实现的产物。
// 它是低级的、旧的，并且在Go当前的HTTP堆栈中未使用。
// 我们应该在Go 1之前删除它。
// 
// 已弃用：请改用包net/http中的客户端或传输。
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ClientConn{
		c:        c,
		r:        r,
		pipereq:  make(map[*http.Request]uint),
		writeReq: (*http.Request).Write,
	}
}

// NewProxyClientConn是Go早期HTTP实现的产物。
// 它是低级的、旧的，并且在Go当前的HTTP堆栈中未使用。
// 我们应该在Go 1之前删除它。
// 
// 已弃用：改用包net/http中的客户端或传输。
func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
	cc := NewClientConn(c, r)
	cc.writeReq = (*http.Request).WriteProxy
	return cc
}

// Hijack会分离ClientConn并返回底层连接以及可能有一些剩余数据的读取端bufio。劫持可能是
// 在用户或Read发出保持活动结束信号之前调用
// 逻辑。在读取或写入过程中，用户不应调用劫持。
func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	c = cc.c
	r = cc.r
	cc.c = nil
	cc.r = nil
	return
}

// Close调用Hijack，然后还关闭底层连接。
func (cc *ClientConn) Close() error {
	c, _ := cc.Hijack()
	if c != nil {
		return c.Close()
	}
	return nil
}

// 写入请求。如果连接
// 已在HTTP保持活动状态下关闭，则返回ErrPersistEOF错误。如果req.Close等于true，则此请求后
// 保持活动连接在逻辑上关闭，并通知对方
// 服务器。ErrUnexpectedEOF表示远程关闭了
// 底层TCP连接，这通常被认为是正常关闭。
func (cc *ClientConn) Write(req *http.Request) error {
	var err error

	// 确保有序执行写入
	id := cc.pipe.Next()
	cc.pipe.StartRequest(id)
	defer func() {
		cc.pipe.EndRequest(id)
		if err != nil {
			cc.pipe.StartResponse(id)
			cc.pipe.EndResponse(id)
		} else {
			// 记住此请求的管道id 
			cc.mu.Lock()
			cc.pipereq[req] = id
			cc.mu.Unlock()
		}
	}()

	cc.mu.Lock()
	if cc.re != nil { // 如果读取端关闭或断开
		defer cc.mu.Unlock()
		return cc.re
	}
	if cc.we != nil {
		defer cc.mu.Unlock()
		return cc.we
	}
	if cc.c == nil { // 用户同时关闭连接
		defer cc.mu.Unlock()
		return errClosed
	}
	c := cc.c
	if req.Close {
		// 我们将EOF写入写入写入端错误，由于存在
		// 可能仍有一些流水线读取
		cc.we = ErrPersistEOF
	}
	cc.mu.Unlock()

	err = cc.writeReq(req, c)
	cc.mu.Lock()
	defer cc.mu.Unlock()
	if err != nil {
		cc.we = err
		return err
	}
	cc.nwritten++

	return nil
}

// Pending返回在连接上发送的未响应请求
// 的数量。
func (cc *ClientConn) Pending() int {
	cc.mu.Lock()
	defer cc.mu.Unlock()
	return cc.nwritten - cc.nread
}

// Read从连线读取下一个响应。有效的响应可能是
// 并返回ErrPersistEOF，这意味着远程
// 请求这是最后一个得到服务的请求。Read可以称为
// 与Write同时进行，但不能与其他Read同时进行。
func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
	// 检索此请求/响应对的管道ID 
	cc.mu.Lock()
	id, ok := cc.pipereq[req]
	delete(cc.pipereq, req)
	if !ok {
		cc.mu.Unlock()
		return nil, ErrPipeline
	}
	cc.mu.Unlock()

	// 确保管道顺序
	cc.pipe.StartResponse(id)
	defer cc.pipe.EndResponse(id)

	cc.mu.Lock()
	if cc.re != nil {
		defer cc.mu.Unlock()
		return nil, cc.re
	}
	if cc.r == nil { // 同时用户关闭连接
		defer cc.mu.Unlock()
		return nil, errClosed
	}
	r := cc.r
	lastbody := cc.lastbody
	cc.lastbody = nil
	cc.mu.Unlock()

	// 确保主体已完全消耗，即使用户不调用body.Close 
	if lastbody != nil {
		// body.Close被假定为幂等函数，并且多次调用
		// 它应该返回其第一次调用
		// 返回的错误。
		err = lastbody.Close()
		if err != nil {
			cc.mu.Lock()
			defer cc.mu.Unlock()
			cc.re = err
			return nil, err
		}
	}

	resp, err = http.ReadResponse(r, req)
	cc.mu.Lock()
	defer cc.mu.Unlock()
	if err != nil {
		cc.re = err
		return resp, err
	}
	cc.lastbody = resp.Body

	cc.nread++

	if resp.Close {
		cc.re = ErrPersistEOF // 不要再发送任何请求
		return resp, cc.re
	}
	return resp, err
}

// Do是写入请求和读取响应的方便方法。
func (cc *ClientConn) Do(req *http.Request) (*http.Response, error) {
	err := cc.Write(req)
	if err != nil {
		return nil, err
	}
	return cc.Read(req)
}
